/*
 *  Copright: 2008 Philipp Leitner, Distributed Systems Group,
 *            TU Wien, leitner@infosys.tuwien.ac.at
 *
 *  This file is part of DAIOS.
 *
 *  DAIOS is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as
 *  published by the Free Software Foundation.
 * 
 *  DAIOS is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with DAIOS.  If not, see
 *  <http://www.gnu.org/licenses/>.
 * 
 */

package at.ac.tuwien.infosys.dsg.daiosPlugins.axis2;

import java.io.IOException;
import java.net.URL;
import java.util.logging.Logger;

import javax.wsdl.WSDLException;
import javax.xml.stream.XMLStreamException;

import at.ac.tuwien.infosys.dsg.daios.exceptions.AmbigiousException;
import at.ac.tuwien.infosys.dsg.daios.framework.DaiosInterceptor;
import at.ac.tuwien.infosys.dsg.daios.framework.ServiceFrontend;
import at.ac.tuwien.infosys.dsg.daios.framework.ServiceFrontendFactory;
import at.ac.tuwien.infosys.dsg.daios.framework.interfaces.IConstants;
import at.ac.tuwien.infosys.dsg.daios.framework.interfaces.IServiceFrontendImplementor;
import at.ac.tuwien.infosys.dsg.daios.util.Utility;
import at.ac.tuwien.infosys.dsg.daios.wsdl.impl.WSDLUtil;

/**
 * 
 * Concrete factory class that creates new Axis2 service invokers.
 * 
 * <p>
 * 
 * Implements the <i>Factory Method</i> pattern of GoF.
 * 
 * @author philipp
 *
 */
public class Axis2ServiceInvokerFactory extends ServiceFrontendFactory {
	
	private Logger log = null;
	
	/**
	 * Construct a new Axis2ServiceInvokerFactory.
	 *
	 */
	public Axis2ServiceInvokerFactory() {
		log = Logger.getLogger(IConstants.LOG_NAME);
	}
	
	/**
	 * Create a new Axis2 invoker.
	 * 
	 * @param url The location of the WSDL definition file.
	 * @return The newly instantiated invoker.
	 * 
	 * @throws WSDLException If an error occurs while retrieving or
	 * parsing the WSDL definition.
	 * @throws AmbigiousException 
	 * @throws XMLStreamException 
	 * @throws IOException 
	 */
	public ServiceFrontend createFrontend(URL url)
		throws WSDLException, AmbigiousException, IOException, XMLStreamException {
		
		String document = null;
		String style = null;
		if(url == null)
			style = IConstants.REST_STYLE;
		else {
			document = Utility.getDocumentFromURL(url);
			style = WSDLUtil.guessInvocationStyle(document);
		}
		log.info("Using invocation style "+style);
		if(url != null)
			log.info("Creating frontend to URL "+url.toExternalForm());
		
		IServiceFrontendImplementor imp =
			Axis2InvokerTable.getInstance(style, url, null);
		
		return new Axis2InvocationFrontend(imp);
		
	}
	
	/**
	 * Create a new invoker that is not linked to any interface
	 * or example (i.e. it has to be a REST GET invocation).
	 * 
	 * <p>
	 * 
	 * The exceptions thrown in this method are thrown only for
	 * compatiblity with createFrontend(URL url); these exceptions
	 * will not happen and can be ignored.
	 * 
	 * @return The newly instantiated invoker.
	 * @throws IOException
	 * @throws AmbigiousException 
	 * @throws WSDLException 
	 */	
	public ServiceFrontend createFrontend()
		throws WSDLException, AmbigiousException, IOException {
		
		// using this constructor implies REST-style
		String style = IConstants.REST_STYLE;

		log.info("Using invocation style "+style);
		
		IServiceFrontendImplementor imp =
			Axis2InvokerTable.getInstance(style, null, null);
		
		return new Axis2InvocationFrontend(imp);
		
	}
	
	/**
	 * Create a new invoker, and hook an interceptor for this
	 * invoker. Has to be implemented by the concrete subclassses.
	 * 
	 * @param url The location of the WSDL definition file.
	 * @param interceptor The interceptor that should be hooked
	 * into the frontend.
	 * @return The newly instantiated invoker.
	 * @throws WSDLException If an error occurs while retrieving or
	 * parsing the WSDL definition.
	 * @throws AmbigiousException 
	 * @throws XMLStreamException 
	 * @throws IOException 
	 */	
	public ServiceFrontend createFrontend(URL url,
		DaiosInterceptor interceptor)
		throws WSDLException, AmbigiousException, XMLStreamException, IOException {
		
		if(interceptor != null)
			interceptor.beginFrontendCreation(this, url);

		String document = null;
		String style = null;
		if(url == null)
			style = IConstants.REST_STYLE;
		else {
			document = Utility.getDocumentFromURL(url);
			style = WSDLUtil.guessInvocationStyle(document);
		}
		log.info("Using invocation style "+style);
		if(url != null)
			log.info("Creating frontend to URL "+url.toExternalForm());
		
		IServiceFrontendImplementor imp =
			Axis2InvokerTable.getInstance(style, url, interceptor);
		
		ServiceFrontend frontend = new Axis2InvocationFrontend(imp);
		
		if(interceptor != null)
			interceptor.finishedFrontendCreation(this, url, frontend);
		
		return frontend;
		
	}

	/**
	 * Create a new invoker that is not linked to any interface
	 * or example (i.e. it has to be a REST GET invocation), and
	 * hook an interceptor for this invoker.
	 * 
	 * <p>
	 * 
	 * The exceptions thrown in this method are thrown only for
	 * compatiblity with createFrontend(URL url); these exceptions
	 * will not happen and can be ignored.
	 * 
	 * @param interceptor The interceptor to hook into the frontend.
	 * @return The newly instantiated invoker.
	 * @throws IOException
	 * @throws AmbigiousException 
	 * @throws WSDLException 
	 */
	public ServiceFrontend createFrontend(DaiosInterceptor interceptor)
		throws WSDLException, AmbigiousException, IOException {
		
		if(interceptor != null)
			interceptor.beginFrontendCreation(this, null);

		// using this constructor implies REST-style
		String style = IConstants.REST_STYLE;

		log.info("Using invocation style "+style);
		
		IServiceFrontendImplementor imp =
			Axis2InvokerTable.getInstance(style, null, interceptor);
		
		ServiceFrontend frontend = new Axis2InvocationFrontend(imp);
		
		if(interceptor != null) {
			interceptor.finishedFrontendCreation(this, null, frontend);
			frontend.setInterceptor(interceptor);
		}
		return frontend;
		
	}

	/**
	 * Create a new invoker. Has to be implemented by the
	 * concrete subclassses.
	 * 
	 * <p>
	 * 
	 * Note that this method is slightly faster than the
	 * version without setting the protocol type explicitly
	 * since this version does not need to figure the protocol
	 * out itself.
	 * 
	 * @param url The location of the WSDL definition file.
	 * @param protocol The Web Service procotol to use (SOAP or
	 * REST)
	 * @return The newly instantiated invoker.
	 * @throws WSDLException If an error occurs while retrieving or
	 * parsing the WSDL definition.
	 * @throws AmbigiousException 
	 * @throws XMLStreamException 
	 * @throws IOException 
	 */
	public ServiceFrontend createFrontend(URL url, String protocol)
		throws WSDLException, AmbigiousException, XMLStreamException, IOException {
		
		String style = null;
		if(protocol.equals(IConstants.REST_STYLE))
			style = IConstants.REST_STYLE;
		else if(protocol.equals(IConstants.SOAP_STYLE))
			style = IConstants.SOAP_STYLE;
		else
			throw new UnsupportedOperationException("Protocol "+protocol+" is"+
				" not supported.");
		
		log.info("Using invocation style "+style);
		if(url != null)
			log.info("Creating frontend to URL "+url.toExternalForm());
		
		IServiceFrontendImplementor imp =
			Axis2InvokerTable.getInstance(style, url, null);
		
		return new Axis2InvocationFrontend(imp);
		
	}

	/**
	 * Create a new invoker, and hook an interceptor for this
	 * invoker. Has to be implemented by the concrete subclassses.
	 * 
	 * <p>
	 * 
	 * Note that this method is slightly faster than the
	 * version without setting the protocol type explicitly
	 * since this version does not need to figure the protocol
	 * out itself.
	 * 
	 * @param url The location of the WSDL definition file.
	 * @param protocol The Web Service procotol to use (SOAP or
	 * REST)
	 * @param interceptor The interceptor that should be hooked
	 * into the frontend.
	 * @return The newly instantiated invoker.
	 * @throws WSDLException If an error occurs while retrieving or
	 * parsing the WSDL definition.
	 * @throws AmbigiousException 
	 * @throws XMLStreamException 
	 * @throws IOException 
	 */	
	public ServiceFrontend createFrontend(URL url, String protocol,
		DaiosInterceptor interceptor) throws WSDLException,
		AmbigiousException, XMLStreamException, IOException {
	
		if(interceptor != null)
			interceptor.beginFrontendCreation(this, url);
		
		
		String style = null;
		if(protocol.equals(IConstants.REST_STYLE))
			style = IConstants.REST_STYLE;
		else if(protocol.equals(IConstants.SOAP_STYLE))
			style = IConstants.SOAP_STYLE;
		else
			throw new UnsupportedOperationException("Protocol "+protocol+" is"+
				" not supported.");
		
		log.info("Using invocation style "+style);
		if(url != null)
			log.info("Creating frontend to URL "+url.toExternalForm());
		
		IServiceFrontendImplementor imp =
			Axis2InvokerTable.getInstance(style, url, interceptor);
		
		ServiceFrontend frontend = new Axis2InvocationFrontend(imp);
		
		if(interceptor != null)
			interceptor.finishedFrontendCreation(this, url, frontend);
		
		return frontend;
		
	}
	
}
